package com.ipan.jfinal.tdo.transform;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ipan.jfinal.tdo.config.Tpl;
import com.ipan.kits.base.ExceptionUtil;
import com.ipan.kits.io.ResourceUtil;
import com.ipan.kits.text.StrFormatter;

/**
 * 注册自定义方法
 * 
 * @author iPan
 * @date 2022-01-26
 */
public final class DefineMethodRegister {
	private static DefineMethodRegister _ME = new DefineMethodRegister();
	private Map<String, DefineMethod> _context = new HashMap<String, DefineMethod>();
	private Logger logger = LoggerFactory.getLogger(getClass());

	private DefineMethodRegister() {}
	
	public static DefineMethodRegister me() {
		return _ME;
	}
	
	public void autoRegister(String classPath) {
		String filePath = classPath.replace(".", "/");
		URL url = ResourceUtil.asUrl(filePath); // 比如：com/qingyu/transform/define
		String protocol = url.getProtocol();
		List<String> result = null;
		// 加载
		if ("file".equals(protocol)) {  
       	    result = findClassLocal(url, classPath);
        } else if ("jar".equals(protocol)) {  
            result = findClassJar(url, classPath);  
        }
		// 注册
		try {
			if (result != null && result.size() > 0) {
				for (String className : result) {
					Class<DefineMethod> defineClass = (Class<DefineMethod>) Class.forName(className);
					DefineMethod defineObject = defineClass.newInstance();
					register(defineObject);
					logger.info("注册自定义方法实现类{}", className);
				}
			}
		} catch(Exception e) {
			logger.error("自动注册转换器的自定义方法，失败！", e);
			ExceptionUtil.unchecked(e); // 注册失败，会导致程序启动失败！
		}
	}
	
	private List<String> findClassLocal(URL url, String classPath) {
		List<String> result = new ArrayList<String>();
		File file = new File(url.getFile());
		File[] files = file.listFiles(new FileFilter() {
			public boolean accept(File chiFile) {
				if(chiFile.isFile() && chiFile.getName().endsWith(".class")){
					return true;
				}
				return false;
			}
		});
		if (files != null && files.length > 0) {
			for (File f : files) {
				String name = f.getName();
				name = name.substring(0, name.lastIndexOf("."));
				String cp = StrFormatter.format("{}.{}", classPath, name);
				result.add(cp);
			}
		}
		return result.size() < 1 ? null : result;
	}
	
	private List<String> findClassJar(URL url, String classPath){
		List<String> result = new ArrayList<String>();
		JarFile jarFile  = null;
		try {
			JarURLConnection jarURLConnection  = (JarURLConnection )url.openConnection();
			jarFile = jarURLConnection.getJarFile();
			Enumeration<JarEntry> jarEntries = jarFile.entries();
			String regex = StrFormatter.format("^{}/(\\w+\\.class)$", classPath.replace(".", "/"));
	        while (jarEntries.hasMoreElements()) {
	            JarEntry jarEntry = jarEntries.nextElement();
	            String jarEntryName = jarEntry.getName();
	            if (Pattern.matches(regex, jarEntryName)) {
	            	String cp = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
	            	result.add(cp);
	            }
	        }
		} catch (IOException e) {
			logger.error("自动注册转换器的自定义方法，失败！", e);
			ExceptionUtil.unchecked(e); // 注册失败，会导致程序启动失败！
		} finally {
			if (jarFile != null) {
				try {
					jarFile.close();
				} catch (IOException e) {
				}
			}
		}
		return result.size() < 1 ? null : result;
	 }
	
	public void register(DefineMethod method) {
		_context.put(method.name(), method);
	}
	
	public DefineMethod getMethod(String key) {
		return _context.get(key);
	}
	
	public String execute(String key, String params, Map rowMap, Object rowKey, Tpl config) {
		DefineMethod define = getMethod(key);
		if (define == null) {
			return "";
		}
		String result = define.call(rowMap, rowKey, params, config);
		return TransducerUtil.nullToEmpty(result);
	}
	
	/**
	 * 自定义方法
	 */
	public static interface DefineMethod {
		/**
		 * 方法名称
		 */
		public String name();
		
		/**
		 * 回调接口
		 * @param rowMap 源文件当前行数据（excel文件格式是Map<Integer, String>、json格式是Map<String, Object>）
		 * @param rowKey 源文件当前列下标
		 * @param params 自定义参数（允许携带一个自定义参数，多个参数使用逗号分隔）
		 * @param config 导入模板配置信息
		 * @return 返回转换后字符串
		 */
		public String call(Map rowMap, Object rowKey, String params, Tpl config);
//		public String call(Map rowMap, Object rowKey, String params, AnalysisContext context, Tpl config);
	}
	
}
